package com.xyht.sca_s.student_manage_system.modules.websocket;


import com.xyht.sca_s.student_manage_system.auth.util.JwtTokenUtil;
import com.xyht.sca_s.student_manage_system.modules.websocket.entity.WebsocketResult;
import com.xyht.sca_s.student_manage_system.modules.websocket.myEnum.WebsocketResultEnum;
import com.xyht.sca_s.student_manage_system.modules.websocket.service.WebSocketService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import static com.xyht.sca_s.student_manage_system.modules.websocket.constant.WebsocketConstant.MAX_WEBSOCKET_CONNECT_NUM;


@ServerEndpoint("/websocket/{token}/{clientFlag}")
@Component
@Log4j2
public class WebSocketCommunication {

    static WebSocketService webSocketService;

    @Autowired
    public void setWebSocketService(WebSocketService webSocketService) {
        WebSocketCommunication.webSocketService = webSocketService;
    }

    static JwtTokenUtil jwtTokenUtil;

    @Autowired
    public void setJwtTokenUtil(JwtTokenUtil jwtTokenUtil) {
        WebSocketCommunication.jwtTokenUtil = jwtTokenUtil;
    }

    /**
     * 用来记录当前在线连接数。设计成线程安全的。
     */
    private static AtomicInteger onlineCount = new AtomicInteger(0);
    /**
     * 用于保存uri对应的连接服务，{uri:WebSocketServer}，设计成线程安全的
     */
    public static ConcurrentHashMap<String, WebSocketCommunication> webSocketServerMAP = new ConcurrentHashMap<>();
    public Session session;// 与某个客户端的连接会话，需要通过它来给客户端发送数据
    public String user_id; //客户端消息发送者
    public Integer client_flag; //客户端标志位
    public String key; //连接的uri

    /**
     * 连接建立成功调用的方法
     *
     * @param session session为与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(@PathParam("token") String token, @PathParam("clientFlag") Integer clientFlag, Session session) {
        try {
            this.session = session;
            this.client_flag = clientFlag;
            log.debug("校验前，websocket连接,session：" + session.getId());
            log.debug("当前链接数：" + getOnlineCount());
            this.user_id = jwtTokenUtil.getUserIdFromToken(token);
            this.key = user_id + "_" + client_flag;
            if (user_id == null || clientFlag == null) {
                session.getBasicRemote().sendText("无效参数，无法连接");
                log.debug("无效Token，无法连接");
                session.close();
                return;
            }
            if (getOnlineCount() > MAX_WEBSOCKET_CONNECT_NUM) {
                session.getBasicRemote().sendText("已达到最大连接,无法再进行websocket连接");
                log.debug("websocket已达到最大连接，无法再进行websocket连接");
                session.close();
                return;
            }

            WebSocketCommunication webSocketServer = webSocketServerMAP.get(key);
            if (webSocketServer != null) { //同样业务的连接已经在线，则把原来的挤下线。
                webSocketService.singleSend(user_id, client_flag, WebsocketResult.failed(WebsocketResultEnum.SOCKET_REPEAT));
                webSocketServer.session.close();//关闭连接，触发关闭连接方法onClose()
            }

            webSocketServerMAP.put(key, this);//保存uri对应的连接服务
            addOnlineCount();
//            webSocketService.singleSend(user_id,client_flag,WebsocketResult.success(WebsocketResultEnum.SUCCESS,"连接了？？？？"));

            log.debug("校验后，收到websocket请求，sessionID:" + session.getId());
            log.debug("当前链接数：" + getOnlineCount());
//            log.debug("request.getHeader(\"token\");：" +request.getHeader("token"));
        } catch (Exception e) {
            e.printStackTrace();
            try {
                session.getBasicRemote().sendText("程序异常");
                log.debug("程序异常");
                session.close();
            }catch (Exception e1){
                e1.printStackTrace();
            }
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        WebSocketCommunication webSocketServer = webSocketServerMAP.get(key);
        if (webSocketServer != null) { //同样业务的连接已经在线，则把原来的挤下线。
            webSocketServerMAP.remove(key);//删除uri对应的连接服务
            reduceOnlineCount(); // 在线数减1
            log.debug("断开连接+++++++++++++++++"+key);
            log.debug("当前链接数：" + getOnlineCount());
        }

    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(@PathParam("pageCode") String pageCode, String message, Session session) {
        log.debug("websocket received message:" + message);
//        try {
//            session.getBasicRemote().sendText("链接上了" + message);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        try {
//            session.getBasicRemote().sendText(message);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        webSocketService.MessageHandle(message, session, pageCode);
    }

    /**
     * 发生错误时调用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.debug("发生错误" + error.toString());
    }

    /**
     * 获取在线连接数
     *
     * @return
     */
    public static int getOnlineCount() {
        return onlineCount.get();
    }

    /**
     * 原子性操作，在线连接数加一
     */
    public static void addOnlineCount() {
        onlineCount.getAndIncrement();
    }

    /**
     * 原子性操作，在线连接数减一
     */
    public static void reduceOnlineCount() {
        onlineCount.getAndDecrement();
    }

}
